////////////////////////////////////////////////////////////////////
// Gestion de l'Iso de Chrono Cross
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
// Nemesis pour Terminus Traduction (tt_nemesis@yahoo.fr)
// Date de création :		30/07/03
// Dernière modification :	30/07/03
////////////////////////////////////////////////////////////////////

// Entete
#include "Patcheur.h"

// Fichier iso
FILE *iso_f;
// Numéro du premier secteur par défaut
int align=150;

// Entete de secteurs sur l'iso
unsigned char SECT_DEBUT[] =		{0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00};
unsigned char SECT_SUB_FICH[] =		{0x00,0x00,0x08,0x00,0x00,0x00,0x08,0x00};
unsigned char SECT_SUB_FIN[] =		{0x00,0x00,0x89,0x00,0x00,0x00,0x89,0x00};

/*------------------------------------------------------------------
  Initialisation de l'iso (ouverture)
------------------------------------------------------------------*/
int Iso_Ouvre (char *iso)
{
	// Test d'ouverture de fichier
	iso_f=fopen(iso,"rb");

	// Erreur d'ouverture ?
	if (iso_f==NULL)
		return ERROR_ISO;
	else {
		fclose(iso_f);
		// Réouverture en écriture
		iso_f=fopen(iso,"r+b");
		return ERROR_NONE;
	}
}

/*------------------------------------------------------------------
  Fermeture de l'iso
------------------------------------------------------------------*/
int Iso_Ferme (void)
{
	// Erreur de fermeture ;)
	if (iso_f==NULL)
		return ERROR_FILE;
	else {
		fclose(iso_f);
		return ERROR_NONE;
	}
}

/*------------------------------------------------------------------
  Taille de l'iso
------------------------------------------------------------------*/
int Iso_Taille (int *taille)
{
	// Erreur de fermeture ;)
	if (iso_f==NULL)
		return ERROR_FILE;
	else {
		fseek(iso_f,0,SEEK_END);
		*taille = ftell(iso_f);
		fseek(iso_f,0,SEEK_SET);
		return ERROR_NONE;
	}
}

// Toutes les fonctions qui suivent ne testent
// pas si l'iso a bien été ouverte, attention !
/*------------------------------------------------------------------
  Renvoie de la position dans l'iso
------------------------------------------------------------------*/
int Iso_Position (void)
{
	return(ftell(iso_f));
}

/*------------------------------------------------------------------
  Saut sur un secteur quelconque de l'iso
--------------------------------------------------------------------
 <- secteur : secteur où l'on souhaite se rendre
------------------------------------------------------------------*/
void Iso_Secteur_Saut (unsigned int secteur)
{
	fseek(iso_f,(secteur+150-align)*SECTEUR_TOTAL,SEEK_SET);
}

/*------------------------------------------------------------------
  Saut par dessus les ECC
------------------------------------------------------------------*/
void Iso_ECC_Saut (void)
{
	fseek(iso_f,SECTEUR_ECC,SEEK_CUR);
}

/*------------------------------------------------------------------
  Saut par dessus l'entete de secteur
------------------------------------------------------------------*/
void Iso_Entete_Saut (void)
{
	fseek(iso_f,SECTEUR_ENTETE,SEEK_CUR);
}

/*------------------------------------------------------------------
  Modification de l'entête d'un secteur
--------------------------------------------------------------------
 <- type : type de secteur SECT_TFICH, SECT_TFIN, SECT_TAUTRE
------------------------------------------------------------------*/
void Iso_Entete_Modif (int type)
{
	unsigned char debut[SECTEUR_DEBUT];

	// Lecture du début de secteur (toujours pareil)
	fread(debut,sizeof(char),SECTEUR_DEBUT,iso_f);
	// Est-ce bien une entete de secteur (debug)
	// Saut du numéro de secteur
	fseek(iso_f,SECTEUR_NUM,SEEK_CUR);
	// Type de secteur (SUB)
	switch (type) {
	case SECT_TFICH:
		fwrite(SECT_SUB_FICH,sizeof(char),SECTEUR_SUB,iso_f);
		break;
	case SECT_TFIN:
		fwrite(SECT_SUB_FIN,sizeof(char),SECTEUR_SUB,iso_f);
		break;
	default:
		fseek(iso_f,SECTEUR_SUB,SEEK_CUR);
	}
}
/*------------------------------------------------------------------
  Test de début de secteur (SECT_DEBUT)
--------------------------------------------------------------------
 <- debut : balise de secteur à tester
 -> renvoie 0 si identiques, premier octet de différence
	en partant de la fin sinon
------------------------------------------------------------------*/
int Iso_Test_Debut (unsigned char debut[SECTEUR_DEBUT])
{
	int c;

	for(c=SECTEUR_DEBUT-1;c>=0 && debut[c]==SECT_DEBUT[c];c--);
	if (c==-1)
		c=OUI;
	else
		c=NON;

	return(c);
}

/*------------------------------------------------------------------
  Test de sous-entete (SECT_SUB)
--------------------------------------------------------------------
 <- debut : balise de secteur à tester
 -> renvoie 0 si identiques, premier octet de différence
	en partant de la fin sinon
------------------------------------------------------------------*/
int Iso_Test_Sub (unsigned char sub[SECTEUR_SUB])
{
	int c;

	for(c=SECTEUR_SUB-1;c>=0 && sub[c]==SECT_SUB_FIN[c];c--);
	if (c>=0) {
		for(c=SECTEUR_SUB-1;c>=0 && sub[c]==SECT_SUB_FICH[c];c--);
		if (c>=0)
			c=SECT_TAUTRE;
		else
			c=SECT_TFICH;
	} else
		c=SECT_TFIN;

	return(c);
}

/*------------------------------------------------------------------
  Lecture de l'entête d'un secteur
--------------------------------------------------------------------
 <- test : test a effectuer ou non sur l'entete
 -> renvoie le type de secteur SECT_TFICH, SECT_TFIN, SECT_TAUTRE
------------------------------------------------------------------*/
int Iso_Entete_Lit (int test)
{
	unsigned char debut[SECTEUR_DEBUT];
	unsigned char sub[SECTEUR_SUB];

	// Lecture du début de secteur (toujours pareil)
	fread(debut,sizeof(char),SECTEUR_DEBUT,iso_f);
	// Est-ce bien une entete de secteur (debug)
	if (test==OUI) {
		if (Iso_Test_Debut(debut)==NON)
			return SECT_ERREUR;
	}
	// Saut du numéro de secteur
	fseek(iso_f,SECTEUR_NUM,SEEK_CUR);
	// Type de secteur (SUB)
	fread(sub,sizeof(char),SECTEUR_SUB,iso_f);

	return(Iso_Test_Sub(sub));
}

/*------------------------------------------------------------------
  Lecture du numéro de secteur du premier secteur
--------------------------------------------------------------------
 -> renvoie le numéro de secteur
------------------------------------------------------------------*/
int Iso_Align ()
{
	unsigned char buf[SECTEUR_NUM];

	// Saut du début de secteur
	fseek(iso_f,SECTEUR_DEBUT,SEEK_SET); // On part du début
	// Lecture du numéro de secteur (toujours pareil)
	fread(buf,sizeof(char),SECTEUR_NUM,iso_f);
	// Retour au début de l'iso
	fseek(iso_f,0L,SEEK_SET);

	// Analyse du numéro
	align=buf[0]%16;
	buf[0]/=16;
	align+=buf[0]*10;
	align*=60;
	align+=buf[1]%16;
	buf[1]/=16;
	align+=buf[1]*10;	
	align*=75;
	align+=buf[2]%16;
	buf[2]/=16;
	align+=buf[2]*10;

	return align;
}

/*------------------------------------------------------------------
  Saut sur place pour corriger les bugs de fopen(..."r+")
  (cf documentation de la fonction)
------------------------------------------------------------------*/
void Iso_Flush (void)
{
	fseek(iso_f,0L,SEEK_CUR);
}

/*------------------------------------------------------------------
  Lecture d'adresses dans un secteur
------------------------------------------------------------------*/
void Iso_Adresses_Lit (unsigned int *buffer)
{
	fread(buffer,sizeof(int),SECTEUR_DONNEES/4,iso_f);
}

/*------------------------------------------------------------------
  Ecriture d'adresses dans un secteur
------------------------------------------------------------------*/
int Iso_Adresses_Ecrit (unsigned int *buffer)
{
	return Iso_Secteur_Insere((unsigned char *)buffer);
}

/*------------------------------------------------------------------
  Copie d'un secteur vers un fichier
--------------------------------------------------------------------
 <- fich : fichier où les données sont écrites
------------------------------------------------------------------*/
void Iso_Secteur_Extrait(FILE *fich)
{
	char buffer[SECTEUR_TOTAL];

	fread(buffer,sizeof(char),SECTEUR_TOTAL,iso_f);	
	fwrite(buffer,sizeof(char),SECTEUR_TOTAL,fich);	
}

/*------------------------------------------------------------------
  Copie des donnees d'un secteur vers un fichier
--------------------------------------------------------------------
 <- fich : fichier où les données sont écrites
 <- 8*fin : distance d'arret à la fin des donnees
	(dans le cas d'un secteur de fin de fichier)
------------------------------------------------------------------*/
void Iso_Donnees_Extrait(FILE *fich, unsigned char fin)
{
	char buffer[SECTEUR_DONNEES];

	fread(buffer,sizeof(char),SECTEUR_DONNEES,iso_f);	
	fwrite(buffer,sizeof(char),SECTEUR_DONNEES-8*fin,fich);	
}

/*------------------------------------------------------------------
  Copie des donnees d'un buffer vers un secteur (+ EDC/ECC)
--------------------------------------------------------------------
 <- donnees : données à insérer
------------------------------------------------------------------*/
int Iso_Secteur_Insere(unsigned char donnees[SECTEUR_DONNEES])
{
	unsigned char buffer[SECTEUR_EDCECC];
	// Position de début de secteur
	_int64 pos;

	// Chargement complet du buffer avec l'entête
	pos = Iso_Position()-SECTEUR_ENTETE;
	fseek(iso_f,(long)pos,SEEK_SET);
	fread(buffer,sizeof(char),SECTEUR_ENTETE,iso_f);
	fseek(iso_f,(long)pos,SEEK_SET);
	// Copie des données
	memcpy(&buffer[SECTEUR_ENTETE],donnees,SECTEUR_DONNEES);
	// 0 pour les EDC/ECC
	memset(&buffer[SECTEUR_ENTETE+SECTEUR_DONNEES],0,SECTEUR_ECC);

	// Calcul des EDC/ECC
	// (par Yazoo, sa version étant plus rapide que la mienne,
	// je ne pensais pas que l'écart se verrait à ce point entre
	// l'optimisée avec table et le calcul bête et méchant)
	do_encode_L2(buffer,MODE_2_FORM_1, 0);

	// Ecriture dans l'iso
	fwrite(buffer,sizeof(char),SECTEUR_TOTAL,iso_f);
	// Test de validité
	if (Iso_Position()%SECTEUR_TOTAL!=0)
		return(ERROR_SECTOR);

	// Tout c'est bien passé
	return ERROR_NONE;
}

/*------------------------------------------------------------------
  Copie des donnees d'un fichier vers un secteur (+ EDC/ECC)
--------------------------------------------------------------------
 <- fich : fichier où les données sont lues
------------------------------------------------------------------*/
int Iso_Donnees_Insere(FILE *fich)
{
	unsigned char donnees[SECTEUR_DONNEES];
	// Nombre d'octets lus
	unsigned int nb;

	nb=fread(donnees,sizeof(char),SECTEUR_DONNEES,fich);	
	// Remplissage de la fin de secteur par des 0
	memset(&donnees[nb],0,SECTEUR_DONNEES-nb);

	return Iso_Secteur_Insere(donnees);
}
